home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / entrdata.zip / ENTRDATA.INC < prev    next >
Text File  |  1993-01-04  |  19KB  |  701 lines

  1. { entrdata.inc - Data entry procedures for entrdata.pas }
  2.  
  3. function InsertOn: boolean;
  4. const InsertStateBit=$80;  { Bit 7 }
  5. var  KeyStatus: byte absolute $0040:$0017;
  6. begin
  7.   InsertOn := (KeyStatus and InsertStateBit)<>0;
  8. end;
  9.  
  10. procedure ToggleNumLock (Switch: Toggle);
  11. const
  12.   LastNumLockBit: byte = 0;   { dummy assumption }
  13.   NumLockBit           = $20; { bit 5 }
  14. var  KeyStatus: byte absolute $0000:$0417;
  15. begin
  16.   if (TopEntry.TypeOfData<Strings) and AutoNumLock then
  17.     case Switch of
  18.       On:  begin
  19.              LastNumLockBit := KeyStatus and NumLockBit;
  20.              KeyStatus      := KeyStatus or  NumLockBit;
  21.            end;
  22.       Off: KeyStatus := (KeyStatus and $DF) or LastNumLockBit;
  23.     end;
  24. end;
  25.  
  26. procedure CallTranslate;  { indirect }
  27. inline ($FF/$1E/TopEntry+11);
  28.   {  call DWORD PTR [>TopEntry.TranslateProc] }
  29.  
  30. procedure CallCheckRange;  { indirect }
  31. inline ($FF/$1E/TopEntry+15);
  32.   {  call DWORD PTR [>TopEntry.CheckRangeProc] }
  33.  
  34. procedure CallErrHandler;  { indirect }  {Added [GAF]}
  35. inline ($FF/$1E/DataPad+10);
  36.   {  call DWORD PTR [>DataPad.ErrHandlerProc] }
  37.  
  38. procedure TransferData (VAR UserVariable);
  39. var
  40.   Size:      byte;
  41.   StrLength: byte absolute UserVariable;
  42. begin
  43.   with TopEntry,DataPad do
  44.     begin
  45.       case TypeOfData of
  46.         Bytes,Chars,ShortInts: Size:=1;
  47.         Words,Integers:        Size:=2;
  48.         LongInts:              Size:=4;
  49.         Reals:                 Size:=6;
  50.       else
  51.         if StoreMode then
  52.              Size := succ( MinI( ord(Sdata[0]),MaxField ))
  53.         else Size := succ(StrLength);
  54.       end;
  55.       if StoreMode then
  56.         Move16 (Bdata,UserVariable,Size)
  57.       else
  58.         begin
  59.           Ldata := 0;    { Clear first }
  60.           Move16 (UserVariable,Bdata,Size);
  61.         end;
  62.     end
  63. end;
  64.  
  65. procedure StripLeadingSpaces (Field: byte);
  66. var
  67.   i: integer;
  68. begin
  69.   if DataStrL>0 then
  70.     begin
  71.       i := 1;
  72.       while (DataStr[i]=' ') and (i<Field) do
  73.         inc(i);
  74.       DataStrL := succ(Field-i);
  75.       Move16 (DataStr[i],DataStr[1],DataStrL);
  76.     end;
  77. end;
  78.  
  79. procedure ConvertDataToStr;
  80. begin
  81.   with TopEntry,DataPad do
  82.     begin
  83.       StoreMode := false;
  84.       TransferData (VarAddr^);
  85.       case TypeOfData of
  86.         Bytes..Words,LongInts: DataStr := StrL (Ldata);
  87.         ShortInts:             DataStr := StrL (SIdata);
  88.         Integers:              DataStr := StrL (Idata);
  89.         Reals:
  90.           begin
  91.             if Decimals<0 then
  92.               DataStr := StrRF (Rdata,Field)
  93.             else
  94.               begin
  95.                 DataStr := StrRFD (Rdata,Field,Decimals);
  96.                 if DataStrL>Field then
  97.                   DataStr := StrRF (Rdata,Field);
  98.               end;
  99.             StripLeadingSpaces (Field);
  100.           end;
  101.         Chars: DataStr := Cdata;
  102.       else DataStr := Sdata;
  103.       end;  { case }
  104.     end;    { with }
  105. end;
  106.  
  107. procedure ConvertStrToData;
  108. var  i: integer;
  109. begin
  110.   with TopEntry,DataPad do
  111.     begin
  112.       Valid := true;
  113.       case TypeOfData of
  114.         Chars:  if DataStrL=0  then
  115.                      Cdata := #00
  116.                 else Cdata := DataStr[1];
  117.         Reals: begin
  118.                  val (DataStr,Rdata,i);
  119.                  Valid := i=0;
  120.                end;
  121.         Bytes..LongInts:
  122.           begin
  123.             val (DataStr,Ldata,i);
  124.             Valid := i=0;
  125.             if Valid then
  126.               case TypeOfData of
  127.                 Bytes:     Valid := Ldata=Bdata;
  128.                 Words:     Valid := Ldata=Wdata;
  129.                 ShortInts: Valid := Ldata=SIdata;
  130.                 Integers:  Valid := Ldata=Idata;
  131.               end;
  132.           end;
  133.       else  Sdata:=DataStr;
  134.       end;  { case }
  135.       if not Valid then  {Added [GAF]}
  136.         begin
  137.           if ErrHandlerProc<>nil then
  138.             CallErrHandler;
  139.           ExtKey:=false;  {Set keys to force edit to stay here}
  140.           Key:=NullKey;
  141.         end;
  142.       {$ifdef UseMsgLineCode } {HERE - hook for invalid entry}
  143.       if not Valid then
  144.         ShowErrMsg (ord(InvalidEM));  { Invalid Entry message }
  145.       {$endif }
  146.     end;
  147. end;
  148.  
  149. procedure StoreData;
  150. begin
  151.   with TopEntry,DataPad do
  152.     if Valid then
  153.       begin
  154.         RangeOK := true;
  155.         if CheckRangeProc<>nil then
  156.           CallCheckRange;
  157.         DataStored := RangeOK;    { OK to set in advance }
  158.         if DataStored then
  159.           begin
  160.             StoreMode := true;
  161.             TransferData (VarAddr^);
  162.           end
  163.         else
  164.           Key:=NullKey; {To stay in data entry}
  165.     end
  166. end;
  167.  
  168. procedure UpdateField (Attr: integer);
  169. var
  170.   FieldStr,SubStr: string;
  171.   L: byte absolute SubStr;
  172. begin
  173.   with TopEntry,DataPad,TWS do
  174.     begin
  175.       SubStr := copy (DataStr,FieldIndex,Field);
  176.       if Justify=Left then
  177.            FieldStr := StrSL (SubStr,Field)   { Fill up blanks w/ spaces }
  178.       else FieldStr := StrSR (SubStr,Field);
  179.       if DataWriteMode=ScrnRel then
  180.          Qwrite (Row,Col,Attr,FieldStr)
  181.       else
  182.          Qwrite (pred(Wrow+Row),pred(Wcol+Col),Attr,FieldStr);
  183.     end;
  184. end;
  185.  
  186. procedure MoveCursor;
  187. begin
  188.   with TopEntry,DataPad do
  189.     begin
  190.       if DataWriteMode=ScrnRel then
  191.         GotoRC (Row,Col+CursorOfs)
  192.       else
  193.         WGotoRC (Row,Col+CursorOfs);
  194.       if InsertOn then
  195.            SetCursor (CursorHalfBlock)
  196.       else SetCursor (CursorUnderline);
  197.     end;
  198. end;
  199.  
  200. function MaxCursorOfs: byte;
  201. begin
  202.   with TopEntry,DataPad do
  203.     MaxCursorOfs := MinI (DataStrL,Field-Flex);
  204. end;
  205.  
  206. function MaxFieldIndex: byte;
  207. begin
  208.   with TopEntry,DataPad do
  209.     MaxFieldIndex := MaxI (1,succ(DataStrL-Field+Flex));
  210. end;
  211.  
  212. procedure CursorFirst;
  213. begin
  214.   with DataPad do
  215.     begin
  216.       FieldIndex := 1;
  217.       CursorOfs  := 0;
  218.     end;
  219. end;
  220.  
  221. procedure CursorLast;
  222. begin
  223.   with TopEntry,DataPad do
  224.     if MaxField>1 then
  225.       begin
  226.         Flex := byte(MaxField<>Field);
  227.         FieldIndex := MaxFieldIndex;
  228.         CursorOfs  := MaxCursorOfs;
  229.       end
  230.     else CursorFirst;
  231. end;
  232.  
  233. procedure CursorLeft;
  234. begin
  235.   with DataPad do
  236.     begin
  237.       if CursorOfs=0 then
  238.            FieldIndex := MaxI (1,pred(FieldIndex))
  239.       else dec(CursorOfs);
  240.     end;
  241. end;
  242.  
  243. procedure CursorRight;
  244. begin
  245.   with TopEntry,DataPad do
  246.     if MaxField>1 then
  247.       begin
  248.         if CursorOfs=MaxCursorOfs then
  249.              FieldIndex := MinI (succ(FieldIndex),MaxFieldIndex)
  250.         else inc(CursorOfs);
  251.       end;
  252. end;
  253.  
  254. procedure DeleteChar;
  255. begin
  256.   with DataPad do
  257.     Delete (DataStr,FieldIndex+CursorOfs,1);
  258. end;
  259.  
  260. procedure BackSpace;
  261. begin
  262.   with TopEntry,DataPad do
  263.     begin
  264.       if (FieldIndex+CursorOfs>1) or (MaxField=1) then
  265.         begin
  266.           CursorLeft;
  267.           DeleteChar;
  268.           if (FieldIndex>1) and (CursorOfs=0) then
  269.             begin
  270.               CursorLeft;
  271.               CursorRight;
  272.             end;
  273.         end;
  274.     end;
  275. end;
  276.  
  277. procedure ClrDataStr;
  278. begin
  279.   DataStr := '';
  280.   CursorFirst;
  281. end;
  282.  
  283. procedure ToggleInsert;
  284. const  InsertBit = $80;
  285. var  KeyStatus: byte absolute $0040:$0017;
  286. begin
  287.   KeyStatus := KeyStatus xor InsertBit;
  288. end;
  289.  
  290. procedure AddChar;
  291. var  DI: integer;    { DataStr Index }
  292. begin
  293.   with TopEntry,DataPad do
  294.     begin
  295.       if MaxField=1 then
  296.         DataStr := Key    { Just overwrite the charcter }
  297.       else
  298.         begin
  299.           if NewData then
  300.             ClrDataStr;
  301.           DI := FieldIndex+CursorOfs;
  302.           if not InsertOn and (DI<=DataStrL) then
  303.             begin
  304.               DataStr[DI] := Key;
  305.               CursorRight;
  306.             end
  307.           else
  308.             if (DataStrL<MaxField) and (InsertOn or (DI>DataStrL)) then
  309.               begin
  310.                 insert (Key,DataStr,DI);
  311.                 CursorRight;
  312.               end;
  313.         end;
  314.     end;
  315. end;
  316.  
  317. procedure ExtKeyEdit;
  318. begin
  319.   with TopEntry,DataPad do
  320.     begin
  321.       case Key of
  322.         LArrKey:             CursorLeft;
  323.         RArrKey:             CursorRight;
  324.         DelKey:              DeleteChar;
  325.         HomeKey,CtrlLArrKey: CursorFirst;
  326.         EndKey,CtrlRArrKey:  CursorLast;
  327.         InsKey:  ;
  328.         {$ifdef UseHelpWndwCode } {Future help window call here}
  329.         {HelpKey: PullHelpWndw (HelpWndwNum);}
  330.         {$endif }
  331.         {else CallCheckGlobalKeys;} {future global key handler call}
  332.       end      { end case }
  333.     end;
  334. end;
  335.  
  336. procedure NormKeyEdit;
  337. var DI: integer;    { DataStr Index }
  338. begin
  339.   with TopEntry,DataPad do
  340.     begin
  341.       if (Key in EntrySet[SetName]) then
  342.         AddChar
  343.       else
  344.         begin
  345.           case Key of
  346.             ^S:  CursorLeft;
  347.             ^D:  CursorRight;
  348.             ^G:  DeleteChar;
  349.             ^H,BSkey: BackSpace;
  350.             ^A:  CursorFirst;
  351.             ^F:  CursorLast;
  352.             ^Y:  ClrDataStr;
  353.             ^R,^U:
  354.               begin
  355.                 ConvertDataToStr;
  356.                 CursorLast;
  357.               end;
  358.             ^V:  ToggleInsert;
  359.           end      { end case }
  360.         end;
  361.     end;    { with }
  362. end;
  363.  
  364. procedure DisplayField (Attr: integer);
  365. begin
  366.   with TopEntry,DataPad do
  367.     begin
  368.       ConvertDataToStr;
  369.       Justify := JustifyOutput;
  370.       if Justify=Left then
  371.            FieldIndex := 1
  372.       else FieldIndex := MaxI (1,succ(DataStrL-Field));
  373.       if Attr=SameAttr then
  374.         Attr := Oattr;
  375.       UpdateField (Attr);
  376.     end;
  377. end;
  378.  
  379. procedure GetDataEntryRec (Index: word);
  380. begin
  381.   DEI := Index;
  382.   TopEntry := DataEntry^[DEI];
  383. end;
  384.  
  385. procedure DisplayFields; { (DEGroup : DEGroupRec; First,Last: byte); }
  386. var
  387.   i: integer;
  388. begin
  389.   if DEGroup.GroupPtr = nil then {cause error and halt if nil pointer}
  390.     runerror(204);
  391.   DataEntry:=DEGroup.GroupPtr; {Point to proper DE group}
  392.   for i:=First to Last do
  393.     begin
  394.       GetDataEntryRec (i);
  395.       DisplayField (TopEntry.Oattr);
  396.     end;
  397. end;
  398.  
  399. procedure SaveData;
  400. begin
  401.   ConvertStrToData;
  402.   StoreData;
  403. end;
  404.  
  405. procedure EnterData;
  406. begin
  407.   with TopEntry,DataPad do
  408.     begin
  409.       ToggleNumLock (On);
  410.       ConvertDataToStr;
  411.       CursorLast;
  412.       Justify := Left;
  413.       repeat
  414.         if WaitForKbd then
  415.           begin
  416.             UpdateField (Iattr);
  417.             MoveCursor;
  418.           end;
  419.         if not WaitForKbd then
  420.           WaitForKbd:=true
  421.         else
  422.           ReadKbd(ExtKey,Key); {[GAF]}
  423.         if TranslateProc<>nil then
  424.           CallTranslate;
  425.         if ExtKey then
  426.              ExtKeyEdit
  427.         else NormKeyEdit;
  428.         NewData := false;
  429.         if (Key=RetKey) then      { RetKey will even apply from Help window }
  430.           SaveData;
  431.       until (Key=RetKey) or (Key=EscKey) ;
  432.       ToggleNumLock (Off);
  433.     end;  { with TopEntry }
  434. end;
  435.  
  436. procedure Enter; { (DEGroup : DEGroupRec; RecNum: word); }
  437. var
  438.   OldCursor:      word;
  439. begin
  440.   OldCursor := GetCursor;
  441.   if DEGroup.GroupPtr = nil then {cause error and halt if nil pointer}
  442.     runerror(204);
  443.   DataEntry:=DEGroup.GroupPtr; {Point to proper DE group}
  444.   with TopEntry,DataPad do
  445.     begin
  446.       GetDataEntryRec (RecNum);
  447.       if VarAddr = nil then {cause error and halt if nil pointer}
  448.         runerror(204);
  449.       NewData := true;
  450.       EnterData;
  451.       DisplayField (Oattr);
  452.     end;
  453.   SetCursor (OldCursor);
  454. end;
  455.  
  456. procedure MoveCursorToField;
  457. begin
  458.   with TopEntry,DataPad,TWS do
  459.     begin
  460.       CursorOfs:=0;
  461.       if DataWriteMode=ScrnRel then
  462.         Qattr (Row,Col,1,Field,Hattr)
  463.       else
  464.         Qattr (pred(Wrow+Row),pred(Wcol+Col),1,Field,Hattr);
  465.       MoveCursor;
  466.     end;
  467. end;
  468.  
  469. function RollInc (First,NumToRoll,Last: word): word;
  470. begin
  471.   if NumToRoll=Last then
  472.        RollInc:=First
  473.   else RollInc:=succ(NumToRoll);
  474. end;
  475.  
  476. function RollDec (First,NumToRoll,Last: word): word;
  477. begin
  478.   if NumToRoll=First then
  479.        RollDec:=Last
  480.   else RollDec:=pred(NumToRoll);
  481. end;
  482.  
  483. procedure EnterSeq; { (DEGroup : DEGroupRec; First,Last: word; VAR Start: word); }
  484. var
  485.   Edit: boolean;
  486.   Attr: integer;
  487. {}procedure HorizAdj (AdjacentCol,NearestCol: byte);
  488.   var  i: word;
  489.   begin
  490.     for i:=First to Last do
  491.       with DataEntry^[i] do
  492.         if (Row=TopEntry.Row) and
  493.            InRangeW(AdjacentCol,Col,NearestCol) then
  494.           begin
  495.             Start := i;
  496.             NearestCol := Col;
  497.           end;
  498. {}end;
  499. {}procedure HorizEnd (Dir: DirType);
  500.   var
  501.     i:      word;
  502.     FarCol: byte;
  503.   begin
  504.     FarCol := TopEntry.Col;
  505.     for i:=First to Last do
  506.       with DataEntry^[i] do
  507.         if (Row=TopEntry.Row) then
  508.           if ((Dir=Right) and (Col>FarCol)) or
  509.              ((Dir=Left ) and (Col<FarCol)) then
  510.             begin
  511.               Start  := i;
  512.               FarCol := Col;
  513.             end;
  514. {}end;
  515. {}procedure VertAdj (AdjacentRow,NearestRow: byte);
  516.   var
  517.     i:           word;
  518.     NearestCols: byte;
  519.     Cols:        integer;
  520.     Closer:      boolean;
  521.   begin
  522.     NearestCols := 255;
  523.     for i:=First to Last do
  524.       with DataEntry^[i] do
  525.         begin
  526.           Cols := Col-TopEntry.Col;
  527.           if Cols<0 then
  528.             Cols := abs( MinI(Cols+Field,0) );
  529.           if (Row=NearestRow) then
  530.                Closer := Cols<NearestCols
  531.           else Closer := InRangeW (AdjacentRow,Row,NearestRow);
  532.           if Closer then
  533.             begin
  534.               Start := i;
  535.               NearestRow  := Row;
  536.               NearestCols := Cols;
  537.             end;
  538.         end;
  539. {}end;
  540. {}procedure NextField;
  541.   begin
  542.     Start := RollInc (First,Start,Last);
  543. {}end;
  544.  
  545. var
  546.   OldCursor:      word;
  547. begin
  548.   OldCursor := GetCursor;
  549.   if DEGroup.GroupPtr = nil then {cause error and halt if nil pointer}
  550.     runerror(204);
  551.   DataEntry:=DEGroup.GroupPtr; {Point to proper DE group}
  552.   with TopEntry,DataPad do
  553.     begin
  554.       repeat
  555.         GetDataEntryRec (Start);
  556.         if VarAddr = nil then {cause error and halt if nil pointer}
  557.           runerror(204);      {Didn't assign this entry}
  558.         MoveCursorToField;
  559.         if not WaitForKbd then
  560.           WaitForKbd:=true
  561.         else
  562.           ReadKbd(ExtKey,Key); {[GAF]}
  563.         Edit := false;
  564.         if ExtKey then
  565.           case Key of
  566.             UpArrKey:            VertAdj  (pred(TopEntry.Row),  0);{ Prev row }
  567.             DnArrKey:            VertAdj  (succ(TopEntry.Row),255);{ Next row }
  568.             LArrKey:             HorizAdj (pred(TopEntry.Col),  0);{ Prev col }
  569.             RArrKey:             HorizAdj (succ(TopEntry.Col),255);{ Next col }
  570.             CtrlLArrKey,HomeKey: HorizEnd (Left);                { First char }
  571.             CtrlRArrKey,EndKey:  HorizEnd (Right);               { Last char  }
  572.             CtrlHomeKey,PgUpKey: Start := First;
  573.             CtrlEndKey,PgDnKey:  Start := Last;
  574.             ShiftTabKey:         Start := RollDec (First,Start,Last);
  575.             InsKey: ;
  576.             {$ifdef UseHelpWndwCode }
  577.             {HelpKey: PullHelpWndw (1);} {future help here}
  578.             {$endif }
  579.             {else CallCheckGlobalKeys;} {future global key handler here}
  580.           end
  581.         else
  582.           case Key Of
  583.             RetKey:  Edit := true;
  584.             TabKey:  NextField;
  585.             EscKey:  ; { Exit sequence }
  586.             ^V:      ToggleInsert;
  587.           else
  588.             Edit       := true;
  589.             WaitForKbd := false;
  590.           end;
  591.         if Edit then
  592.           begin
  593.             NewData := Key<>RetKey;
  594.             EnterData;
  595.             if (Key=RetKey) and AutoTab then
  596.               NextField;
  597.             case Key of
  598.               RetKey,EscKey:
  599.                 if (Start=DEI) then
  600.                   DisplayField (Hattr);
  601.             end;
  602.             if Key=EscKey
  603.               then Key := #00;
  604.           end;
  605.         if Start<>DEI then
  606.           DisplayField (Oattr);
  607.       until (Key=EscKey) or (ExtKey and (Key=SeqDoneKey));
  608.       DisplayField (Oattr);
  609.     end;  { with }
  610.   SetCursor (OldCursor);
  611. end;
  612.  
  613. function GetJustify (Justify: DirType; TOD: TypeOfDataType): DirType;
  614. begin
  615.   if Justify=NoDir then
  616.     begin
  617.       if TOD<=UserNums then
  618.            GetJustify := Right   { for nums }
  619.       else GetJustify := Left;   { for chars and strings }
  620.     end
  621.   else GetJustify:=Justify;
  622. end;
  623.  
  624. function GetSetName (SN: SetNames; TOD: TypeOfDataType): SetNames;
  625. begin
  626.   if SN=NoSet then
  627.     case TOD of
  628.       Bytes,Words:         GetSetName := UnsignedSet;
  629.       ShortInts..LongInts: GetSetName := SignedSet;
  630.       Reals:               GetSetName := RealSet;
  631.     else
  632.       GetSetName := CharSet;
  633.     end
  634.   else GetSetName:=SN;
  635. end;
  636.  
  637. procedure GetDataEntry; { (DEGroup : DEGroupRec; Index: word); }
  638. begin
  639.   if DEGroup.GroupPtr = nil then {cause error and halt if nil pointer}
  640.     runerror(204);
  641.   DataEntry:=DEGroup.GroupPtr; {Point to proper DE group}
  642.   DEI := Index;
  643.   TopEntry := DataEntry^[DEI];
  644.   fillchar(TopEntry,sizeof(TopEntry),0); {clear it}
  645. end;
  646.  
  647. procedure SaveDataEntry;
  648. begin
  649.   with TopEntry do
  650.     begin
  651.       SetName := GetSetName (SetName,TypeOfData);
  652.       if MaxField=0 then
  653.         MaxField := Field;
  654.       JustifyOutput := GetJustify (JustifyOutput,TypeOfData);
  655.       if Iattr=0 then
  656.         Iattr := DataEntryIattr;  { Default Input  attribute }
  657.       if Oattr=0 then
  658.         Oattr := DataEntryOattr;  { Output attribute }
  659.     end;
  660.   DataEntry^[DEI] := TopEntry;
  661. end;
  662.  
  663. procedure AllocateDataEntries; {(var DEGroup : DEGroupRec; NumEntries : word);}
  664. {Allocates memory for a group of data entries and assigns pointer to group rec}
  665. var
  666.   size: word;
  667. begin
  668.   Size:=sizeof(DataEntryRec)*NumEntries; {memory needed}
  669.   with DEGroup do
  670.     begin
  671.       if InRangeW(1,NumEntries,MaxDataEntries) and HeapOK(Size) then
  672.         begin
  673.           getmem(GroupPtr,Size);
  674.           NumInGroup:=NumEntries;
  675.           fillchar(GroupPtr^,Size,0);
  676.         end
  677.       else
  678.         begin
  679.           GroupPtr:=nil; {range or other error}
  680.           NumInGroup:=0;
  681.         end;
  682.     end; {with}
  683. end;
  684.  
  685. procedure RemoveDataEntries; {(var DEGroup : DEGroupRec);}
  686. {De-allocates DE recs created w/ Create}
  687. begin
  688.   if DEGroup.GroupPtr = nil then {cause error and halt if nil pointer}
  689.     runerror(204);
  690.   with DEGroup do
  691.     begin
  692.       freemem(GroupPtr,sizeof(DataEntryRec)*NumInGroup);
  693.       GroupPtr:=nil; {Clear rec}
  694.       NumInGroup:=0;
  695.     end; {with}
  696. end;
  697.  
  698.  
  699.  
  700.  
  701.